package org.yanfengying.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.yanfengying.constants.WxConstants;
import org.yanfengying.dto.LoginDto;
import org.yanfengying.dto.PasswordDTO;
import org.yanfengying.dto.PhoneLoginDTO;
import org.yanfengying.user.domain.Logininfo;
import org.yanfengying.user.domain.User;
import org.yanfengying.user.domain.Wxuser;
import org.yanfengying.user.mapper.LogininfoMapper;
import org.yanfengying.user.mapper.UserMapper;
import org.yanfengying.user.mapper.WxuserMapper;
import org.yanfengying.user.service.ILogininfoService;
import org.yanfengying.utils.AjaxResult;
import org.yanfengying.utils.HttpClientUtils;
import org.yanfengying.utils.MD5Utils;
import org.yanfengying.utils.service.impl.BastServerImpl;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yanfengying
 * @since 2022-11-14
 */
@Service
public class LogininfoServiceImpl extends BastServerImpl<Logininfo> implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Override
    @Transactional
    public AjaxResult accountLogin(LoginDto dto) {

        //参数获取->参数校验
        String password = dto.getPassword();
        Integer type = dto.getType();
        String username = dto.getUsername();
        if(StringUtils.isEmpty(password) || type == null || StringUtils.isEmpty(username)){
            //向前端返回
            return AjaxResult.me().setSuccess(false).setMessage("参数错误请重新登录");
        }
        //根据用户名查询是否存在该用户信息
        Logininfo logininfo = logininfoMapper.getLogininfoByUsername(dto);

        if(Objects.isNull(logininfo)){//参数为空->用户不存在或者已禁用
            return AjaxResult.me().setSuccess(false)
                    .setMessage("该用户不存在或者被禁用请重新登录");
        }
        //不为空->判断密码->加盐加密后在进行比较
        password = MD5Utils.encrypByMd5("123" + logininfo.getSalt() + "456" + password);
        if(!password.equals(logininfo.getPassword())){
            //密码不匹配
            return AjaxResult.me().setSuccess(false).setMessage("密码错误请核对后重新输入");
        }
        return setLocalhost(logininfo);
    }

    /**
     * 将数据存放到redis并将登录信息传给前端
     * @param logininfo
     * @return
     */
    private AjaxResult setLocalhost(Logininfo logininfo) {
        //登录成功以后要将数据存放到redis中,并设置过期时间
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);

        //将token传到前端
        HashMap<String, Object> result = new HashMap<>();
        result.put("token", token);
        logininfo.setPassword("");
        logininfo.setSalt("");
        result.put("loginInfo", logininfo);
        return AjaxResult.me().setResult(result);
    }

    /**
     * 用户登录->三方
     * @param map
     * @return
     */

    @Override
    @Transactional
    public AjaxResult loginBack(Map<String,Object> map) {
        String code = map.get("code").toString();
        String resultPath = WxConstants.GET_ACK_URL
                .replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE", code);

        //1 根据code获取用户的accessToken和oppenid
        JSONObject jsonObject = JSONObject.parseObject(HttpClientUtils.httpGet(resultPath));
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");

        //2 根据openid查是否存在该用户(wxuser表)->
        Wxuser wxuser = wxuserMapper.loadUserByOpenid(openid);
        if(Objects.nonNull(wxuser)){
            // 存在就直接免密登录->获取用户信息并将数据传给前端
            Long userId = wxuser.getUserId();
            Logininfo logininfo = logininfoMapper.loadByUserId(userId);
            return setLocalhost(logininfo);
        }else{
            // 不存在就跳转绑定页面(交给前端)->将token和openid返回给前端
            HashMap<String, Object> map1 = new HashMap<>();
            map1.put("accessToken",accessToken);
            map1.put("openid",openid);
            return AjaxResult.me().setSuccess(false).setMessage("tobind").setResult(map1);
        }
    }

    @Override
    public AjaxResult loginPhone(PhoneLoginDTO dto) {
        //1 参数校验
        String phone = dto.getPhone();
        String smsCode = dto.getSmsCode();
        Integer type = dto.getType();
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)){
            throw new RuntimeException("参数异常请重新输入!");
        }

        //2 判断验证码是否正确->正确(登录成功)->不正确(返回错误信息)
        String phoneSmsCode = (String)redisTemplate.opsForValue().get("phone_sms_code_" + phone);
        if(StringUtils.isEmpty(phoneSmsCode)){//验证码过期
            throw new RuntimeException("验证码已过期,请重新获取");
        }
        //验证码不正确
        phoneSmsCode = phoneSmsCode.split(":")[0];
        if(!phoneSmsCode.equalsIgnoreCase(smsCode)){//不相等(忽略大小写)
            throw new RuntimeException("验证码不相等,请重新输入");
        }
        //验证码正确->登录(向前端返回信息)
        //4 免密登录->创建一个token->将信息传给前端
        Logininfo logininfo = logininfoMapper.loadByPhone(phone);
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        //将密码和盐值重新设置保证安全性
        logininfo.setPassword("");
        logininfo.setSalt("");
        map.put("loginInfo", logininfo);
        return AjaxResult.me().setResult(map);

    }

    @Override
    public AjaxResult updataPassword(PasswordDTO dto) {
        //1 参数校验
        String confirmPassword = dto.getConfirmPassword();
        String password = dto.getPassword();
        String phone = dto.getPhone();
        String smsCode = dto.getSmsCode();
        if(StringUtils.isEmpty(confirmPassword) || StringUtils.isEmpty(password) || StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)){
            throw new RuntimeException("参数异常请核对后重新输入!");
        }
        if(!password.equals(confirmPassword)){//密码不相等
            throw new RuntimeException("两次密码不相等,请检查后重新输入!");
        }
        //验证码匹配->不相等(抛异常)->相等(修改密码)
        String phoneSmsCode = (String)redisTemplate.opsForValue().get("password_sms_code_" + phone);
        if(StringUtils.isEmpty(phoneSmsCode)){//验证码过期
            throw new RuntimeException("验证码已过期,请重新获取");
        }
        //验证码不正确
        phoneSmsCode = phoneSmsCode.split(":")[0];
        if(!phoneSmsCode.equalsIgnoreCase(smsCode)){//不相等(忽略大小写)
            throw new RuntimeException("验证码不相等,请重新输入");
        }
        //相等(修改密码)->修改logininfo/user表相关信息
        Logininfo logininfo = logininfoMapper.loadByPhone(phone);
        User user = userMapper.loaduUserByphone(phone);
        //完善用户表信息
        password = MD5Utils.encrypByMd5("123" + logininfo.getSalt() + "456" + password);
        logininfo.setPassword(password);
        logininfoMapper.update(logininfo);
        return AjaxResult.me();
    }
}
